package com.fs.common.base.bean.query;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.fs.common.utils.function.TripleFunction;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 更新构建器
 *
 * @author LiuQi 2025/5/6-19:48
 * @version V1.0
 **/
public class QueryBuilder<D, E> {
    private final QueryWrapper<E> queryWrapper;
    private final Function<QueryWrapper<E>, List<D>> queryFunc;
    private final TripleFunction<Long, Long, QueryWrapper<E>, IPage<D>> pageQueryFunc;
    private final BaseMapper<E> baseMapper;

    private Long pageNo;
    private Long pageSize;
    private List<String> excludeFields = new ArrayList<>(16);

    public QueryBuilder(Function<QueryWrapper<E>, List<D>> queryFunc,
                        TripleFunction<Long, Long, QueryWrapper<E>, IPage<D>> pageQueryFunc,
                        BaseMapper<E> baseMapper,
                        QueryWrapper<E> queryWrapper) {
        this.queryFunc = queryFunc;
        this.pageQueryFunc = pageQueryFunc;
        this.baseMapper = baseMapper;
        this.queryWrapper = queryWrapper;
    }

    public static <D, E> QueryBuilder<D, E> create(Function<QueryWrapper<E>, List<D>> queryFunc,
                                                   TripleFunction<Long, Long, QueryWrapper<E>, IPage<D>> pageQueryFunc,
                                                   BaseMapper<E> baseMapper,
                                                   QueryWrapper<E> queryWrapper) {
        return new QueryBuilder<>(queryFunc, pageQueryFunc, baseMapper, queryWrapper);
    }

    public QueryBuilder<D, E> eq(String key, Object value) {
        if (null == value) {
            return this;
        }
        queryWrapper.eq(key, value);
        return this;
    }

    public QueryBuilder<D, E> neq(String key, Object value) {
        if (null == value) {
            return this;
        }
        queryWrapper.ne(key, value);
        return this;
    }

    public QueryBuilder<D, E> in(String key, Collection<?> list) {
        if (CollectionUtils.isEmpty(list)) {
            return this;
        }
        queryWrapper.in(key, list);
        return this;
    }

    public QueryBuilder<D, E> notIn(String key, Collection<?> list) {
        if (CollectionUtils.isEmpty(list)) {
            return this;
        }
        queryWrapper.notIn(key, list);
        return this;
    }

    public QueryBuilder<D, E> like(String key, String val) {
        if (StringUtils.isBlank(val)) {
            return this;
        }
        queryWrapper.like(key, val);
        return this;
    }

    public QueryBuilder<D, E> notLike(String key, String val) {
        if (StringUtils.isBlank(val)) {
            return this;
        }
        queryWrapper.notLike(key, val);
        return this;
    }

    public QueryBuilder<D, E> lt(String key, Object val) {
        if (null == val) {
            return this;
        }
        queryWrapper.lt(key, val);
        return this;
    }

    public QueryBuilder<D, E> le(String key, Object val) {
        if (null == val) {
            return this;
        }
        queryWrapper.le(key, val);
        return this;
    }

    public QueryBuilder<D, E> gt(String key, Object val) {
        if (null == val) {
            return this;
        }
        queryWrapper.gt(key, val);
        return this;
    }

    public QueryBuilder<D, E> ge(String key, Object val) {
        if (null == val) {
            return this;
        }
        queryWrapper.ge(key, val);
        return this;
    }

    public QueryBuilder<D, E> ne(String key, Object val) {
        if (null == val) {
            return this;
        }
        queryWrapper.ne(key, val);
        return this;
    }

    public QueryBuilder<D, E> isNull(String key) {
        queryWrapper.isNull(key);
        return this;
    }

    public QueryBuilder<D, E> isNotNull(String key) {
        queryWrapper.isNotNull(key);
        return this;
    }

    public QueryBuilder<D, E> notNull(String key) {
        queryWrapper.isNotNull(key);
        return this;
    }

    /**
     * 按字段做归并
     * @param columns 归并的列
     * @return 当前对象
     */
    public QueryBuilder<D, E> groupBy(String...columns) {
        queryWrapper.groupBy(Arrays.asList(columns));
        return this;
    }

    /**
     * 指定查询字段
     * @param columns 字段列表
     * @return 当前对象
     */
    public QueryBuilder<D, E> select(String...columns) {
        queryWrapper.select(columns);
        return this;
    }

    /**
     * 增加or条件
     * @param consumer 消费函数
     * @return 当前对象
     */
    public QueryBuilder<D, E> or(Consumer<QueryWrapper<E>> consumer) {
        this.queryWrapper.or(consumer);
        return this;
    }

    /**
     * 增加and条件
     * @param consumer 消费函数
     * @return 当前对象
     */
    public QueryBuilder<D, E> and(Consumer<QueryWrapper<E>> consumer) {
        this.queryWrapper.and(consumer);
        return this;
    }

    public QueryBuilder<D, E> excludeField(String field) {
        excludeFields.add(field);
        return this;
    }

    public QueryBuilder<D, E> excludeFields(List<String> fields) {
        excludeFields = fields;
        return this;
    }

    public QueryBuilder<D, E> setPageNo(Long pageNo) {
        this.pageNo = pageNo;
        return this;
    }

    public QueryBuilder<D, E> setPageSize(Long pageSize) {
        this.pageSize = pageSize;
        return this;
    }

    public QueryBuilder<D, E> orderByDesc(String column) {
        this.queryWrapper.orderByDesc(column);
        return this;
    }

    public QueryBuilder<D, E> orderByAsc(String column) {
        this.queryWrapper.orderByAsc(column);
        return this;
    }

    public QueryBuilder<D, E> orderBy(String column, boolean isAsc) {
        if (isAsc) {
            this.queryWrapper.orderByAsc(column);
        } else {
            this.queryWrapper.orderByDesc(column);
        }
        return this;
    }

    /**
     * 执行查询操作
     * @return 查询结果
     */
    public List<D> query() {
        if (null != pageNo && null != pageSize) {
            long start = (pageNo - 1) * pageSize;
            this.queryWrapper.last("limit " + start + "," + pageSize);
        }
        if (!CollectionUtils.isEmpty(this.excludeFields)) {
            this.queryWrapper.select(item -> !this.excludeFields.contains(item.getColumn()));
        }
        return queryFunc.apply(this.queryWrapper);
    }

    /**
     * 执行查询操作并将查询后的列表数据进行转换
     * @param func 转换函数
     * @return 转换后的数据
     * @param <V> 转换后的对象类型
     */
    public <V> List<V> queryAndConvert(Function<D, V> func) {
        return this.query()
                .stream()
                .map(func)
                .toList();
    }

    /**
     * 执行查询将将结果转换成map
     * @param keyFunc key的转换函数
     * @return 转换后的结果
     * @param <K> key类型
     */
    public <K> Map<K, D> query(Function<D, K> keyFunc) {
        return this.query()
                .stream()
                .collect(Collectors.toMap(keyFunc, d -> d));
    }

    /**
     * 执行查询并将结果转换成map
     * @param keyFunc key的转换函数
     * @param valueFunc value的转换函数
     * @return 转换结果
     * @param <K> key类型
     * @param <V> value类型
     */
    public <K, V> Map<K, V> query(Function<D, K> keyFunc, Function<D, V> valueFunc) {
        return this.query()
                .stream()
                .collect(Collectors.toMap(keyFunc, valueFunc));
    }

    /**
     * 查询map类型的列表结果
     * @return 查询结果
     */
    public List<Map<String, Object>> queryMaps() {
        return this.baseMapper.selectMaps(queryWrapper);
    }

    /**
     * 查找单条记录
     * @return 查找到的记录
     */
    public Optional<D> findOneOpt() {
        return this.query()
                .stream()
                .findAny();
    }

    /**
     * 查找单条记录
     * @return 查找到的记录 可为空
     */
    public D findOne() {
        return this.findOneOpt().orElse(null);
    }

    public IPage<D> pageQuery() {
        if (!CollectionUtils.isEmpty(this.excludeFields)) {
            this.queryWrapper.select(item -> !this.excludeFields.contains(item.getColumn()));
        }
        return pageQueryFunc.apply(this.pageNo, this.pageSize, this.queryWrapper);
    }

    /**
     * 计数
     * @return 数量
     */
    public Long count() {
        return SqlHelper.retCount(this.baseMapper.selectCount(queryWrapper));
    }

    /**
     * 记录是否存在
     */
    public boolean exists() {
        return this.baseMapper.exists(queryWrapper);
    }

    /**
     * 使用queryWrapper进行附加操作
     * @param consumer queryWrapper处理函数
     * @return 当前对象
     */
    public QueryBuilder<D, E> peek(Consumer<QueryWrapper<E>> consumer) {
        consumer.accept(this.queryWrapper);
        return this;
    }
}
